๋ค์ํ ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ๊ฐ๋ ฅํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ API๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํ ํ์ฅ ๊ฐ๋ฅํ GraphQL ์คํค๋ง ๋์์ธ ํจํด์ ์์๋ณด์ธ์. ์คํค๋ง ์คํฐ์นญ, ํ๋๋ ์ด์ , ๋ชจ๋ํ๋ฅผ ๋ง์คํฐํ์ธ์.
GraphQL ์คํค๋ง ๋์์ธ: ๊ธ๋ก๋ฒ API๋ฅผ ์ํ ํ์ฅ ๊ฐ๋ฅํ ํจํด
GraphQL์ ๊ธฐ์กด์ REST API์ ๋ํ ๊ฐ๋ ฅํ ๋์์ผ๋ก ๋ถ์ํ์ฌ, ํด๋ผ์ด์ธํธ์๊ฒ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ ํํ๊ฒ ์์ฒญํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ GraphQL API์ ๋ณต์ก์ฑ๊ณผ ๋ฒ์๊ฐ ์ฆ๊ฐํจ์ ๋ฐ๋ผ, ํนํ ๋ค์ํ ๋ฐ์ดํฐ ์๊ตฌ ์ฌํญ์ ๊ฐ์ง ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ํ ๋, ์ ์คํ ์คํค๋ง ๋์์ธ์ ์ ์ง๋ณด์์ฑ, ํ์ฅ์ฑ ๋ฐ ์ฑ๋ฅ์ ๋งค์ฐ ์ค์ํด์ง๋๋ค. ์ด ๊ธ์์๋ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ตฌ ์ฌํญ์ ์ฒ๋ฆฌํ ์ ์๋ ๊ฐ๋ ฅํ API๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋๋ ์ฌ๋ฌ ํ์ฅ ๊ฐ๋ฅํ GraphQL ์คํค๋ง ๋์์ธ ํจํด์ ์ดํด๋ด ๋๋ค.
ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ์ ์ค์์ฑ
์ ์ค๊ณ๋ GraphQL ์คํค๋ง๋ ์ฑ๊ณต์ ์ธ API์ ๊ธฐ๋ฐ์ ๋๋ค. ์ด๋ ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ์ดํฐ ๋ฐ ์๋น์ค์ ์ํธ ์์ฉํ๋ ๋ฐฉ์์ ๊ฒฐ์ ํฉ๋๋ค. ์๋ชป๋ ์คํค๋ง ๋์์ธ์ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ๋ณ๋ชฉ ํ์: ๋นํจ์จ์ ์ธ ์ฟผ๋ฆฌ์ ๋ฆฌ์กธ๋ฒ๋ ๋ฐ์ดํฐ ์์ค์ ๊ณผ๋ถํ๋ฅผ ์ฃผ๊ณ ์๋ต ์๊ฐ์ ๋ฆ์ถ ์ ์์ต๋๋ค.
- ์ ์ง๋ณด์ ๋ฌธ์ : ๋ชจ๋๋ฆฌ์ ์คํค๋ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฑ์ฅํจ์ ๋ฐ๋ผ ์ดํด, ์์ ๋ฐ ํ ์คํธํ๊ธฐ ์ด๋ ค์์ง๋๋ค.
- ๋ณด์ ์ทจ์ฝ์ : ์๋ชป ์ ์๋ ์ ๊ทผ ์ ์ด๋ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ๋ฌด๋จ ์ฌ์ฉ์์๊ฒ ๋ ธ์ถ์ํฌ ์ ์์ต๋๋ค.
- ์ ํ๋ ํ์ฅ์ฑ: ๊ฐํ๊ฒ ๊ฒฐํฉ๋ ์คํค๋ง๋ ์ฌ๋ฌ ์๋ฒ๋ ํ์ ๊ฑธ์ณ API๋ฅผ ๋ถ์ฐํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค.
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ ์ด๋ฌํ ๋ฌธ์ ๋ค์ ๋์ฑ ์ฆํญ๋ฉ๋๋ค. ์ง์ญ๋ง๋ค ๋ฐ์ดํฐ ์๊ตฌ ์ฌํญ, ๊ท์ ์ ์ฝ, ์ฑ๋ฅ ๊ธฐ๋์น๊ฐ ๋ค๋ฅผ ์ ์์ต๋๋ค. ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ์ ์ด๋ฌํ ๊ณผ์ ๋ค์ ํจ๊ณผ์ ์ผ๋ก ํด๊ฒฐํ ์ ์๊ฒ ํด์ค๋๋ค.
ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ์ ํต์ฌ ์์น
ํน์ ํจํด์ ์ดํด๋ณด๊ธฐ ์ ์ ์คํค๋ง ๋์์ธ์ ์๋ดํด์ผ ํ ๋ช ๊ฐ์ง ํต์ฌ ์์น์ ์ค๋ช ํ๊ฒ ์ต๋๋ค.
- ๋ชจ๋์ฑ: ์คํค๋ง๋ฅผ ๋ ์๊ณ ๋ ๋ฆฝ์ ์ธ ๋ชจ๋๋ก ๋๋๋๋ค. ์ด๋ฅผ ํตํด API์ ๊ฐ๋ณ ๋ถ๋ถ์ ๋ ์ฝ๊ฒ ์ดํด, ์์ ๋ฐ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๊ตฌ์ฑ ๊ฐ๋ฅ์ฑ: ๋ค๋ฅธ ๋ชจ๋์ ์ฝ๊ฒ ๊ฒฐํฉํ๊ณ ํ์ฅํ ์ ์๋๋ก ์คํค๋ง๋ฅผ ๋์์ธํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ธฐ์กด ํด๋ผ์ด์ธํธ๋ฅผ ๋ฐฉํดํ์ง ์๊ณ ์๋ก์ด ๊ธฐ๋ฅ๊ณผ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์ถ์ํ: ์ ์ ์๋ GraphQL ์ธํฐํ์ด์ค ๋ค์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์์ค ๋ฐ ์๋น์ค์ ๋ณต์ก์ฑ์ ์จ๊น๋๋ค. ์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ์ ์ํฅ์ ์ฃผ์ง ์๊ณ ๊ตฌํ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
- ์ผ๊ด์ฑ: ์คํค๋ง ์ ์ฒด์์ ์ผ๊ด๋ ๋ช ๋ช ๊ท์น, ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต์ ์ ์งํฉ๋๋ค. ์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ๊ฐ API๋ฅผ ๋ ์ฝ๊ฒ ๋ฐฐ์ฐ๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ์ต์ ํ: ์คํค๋ง ๋์์ธ์ ๋ชจ๋ ๋จ๊ณ์์ ์ฑ๋ฅ ์ํฅ์ ๊ณ ๋ คํฉ๋๋ค. ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ํ๋ ๋ณ์นญ๊ณผ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๋ฐ ๋คํธ์ํฌ ์์ฒญ ์๋ฅผ ์ต์ํํฉ๋๋ค.
ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ ํจํด
๊ฐ๋ ฅํ GraphQL API๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ๋ช ๊ฐ์ง ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ ํจํด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ์คํค๋ง ์คํฐ์นญ(Schema Stitching)
์คํค๋ง ์คํฐ์นญ์ ์ฌ๋ฌ GraphQL API๋ฅผ ๋จ์ผ ํตํฉ ์คํค๋ง๋ก ๊ฒฐํฉํ๋ ๊ฒ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ์ด๋ ๋ฐ์ดํฐ์ ๋ค๋ฅธ ๋ถ๋ถ์ ๋ด๋นํ๋ ๋ค๋ฅธ ํ์ด๋ ์๋น์ค๊ฐ ์์ ๋ ํนํ ์ ์ฉํฉ๋๋ค. ์ฌ๋ฌ ๊ฐ์ ๋ฏธ๋ API๋ฅผ ๊ฐ์ง๊ณ '๊ฒ์ดํธ์จ์ด' API๋ฅผ ํตํด ํ๋๋ก ํฉ์น๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
์๋ ๋ฐฉ์:
- ๊ฐ ํ์ด๋ ์๋น์ค๋ ์์ฒด ์คํค๋ง๋ฅผ ๊ฐ์ง ์์ฒด GraphQL API๋ฅผ ๋ ธ์ถํฉ๋๋ค.
- ์ค์ ๊ฒ์ดํธ์จ์ด ์๋น์ค๋ ์คํค๋ง ์คํฐ์นญ ๋๊ตฌ(์: Apollo Federation ๋๋ GraphQL Mesh)๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ์คํค๋ง๋ค์ ๋จ์ผ ํตํฉ ์คํค๋ง๋ก ๋ณํฉํฉ๋๋ค.
- ํด๋ผ์ด์ธํธ๋ ๊ฒ์ดํธ์จ์ด ์๋น์ค์ ์ํธ ์์ฉํ๋ฉฐ, ์ด ์๋น์ค๋ ์์ฒญ์ ์ ์ ํ ๊ธฐ๋ณธ API๋ก ๋ผ์ฐํ ํฉ๋๋ค.
์์:
์ ํ, ์ฌ์ฉ์, ์ฃผ๋ฌธ์ ๋ํ ๋ณ๋์ API๊ฐ ์๋ ์ ์์๊ฑฐ๋ ํ๋ซํผ์ ์์ํด ๋ณด์ญ์์ค. ๊ฐ API์๋ ์์ฒด ์คํค๋ง๊ฐ ์์ต๋๋ค.
# Products API
type Product {
id: ID!
name: String!
price: Float!
}
type Query {
product(id: ID!): Product
}
# Users API
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
# Orders API
type Order {
id: ID!
userId: ID!
productId: ID!
quantity: Int!
}
type Query {
order(id: ID!): Order
}
๊ฒ์ดํธ์จ์ด ์๋น์ค๋ ์ด๋ฌํ ์คํค๋ง๋ค์ ํจ๊ป ์ฎ์ด ํตํฉ๋ ์คํค๋ง๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
type Product {
id: ID!
name: String!
price: Float!
}
type User {
id: ID!
name: String!
email: String!
}
type Order {
id: ID!
user: User! @relation(field: "userId")
product: Product! @relation(field: "productId")
quantity: Int!
}
type Query {
product(id: ID!): Product
user(id: ID!): User
order(id: ID!): Order
}
Order ํ์
์ด ์ด์ ๋ณ๋์ API์ ์ ์๋์ด ์์์๋ ๋ถ๊ตฌํ๊ณ User ๋ฐ Product์ ๋ํ ์ฐธ์กฐ๋ฅผ ํฌํจํ๋ ๋ฐฉ์์ ์ฃผ๋ชฉํ์ญ์์ค. ์ด๋ ์คํค๋ง ์คํฐ์นญ ์ง์๋ฌธ(์ด ์์์๋ @relation๊ณผ ๊ฐ์)์ ํตํด ๋ฌ์ฑ๋ฉ๋๋ค.
์ฅ์ :
- ๋ถ์ฐ๋ ์์ ๊ถ: ๊ฐ ํ์ ์์ฒด ๋ฐ์ดํฐ์ API๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ํฅ์๋ ํ์ฅ์ฑ: ๊ฐ API๋ฅผ ํน์ ์๊ตฌ์ ๋ฐ๋ผ ๋ ๋ฆฝ์ ์ผ๋ก ํ์ฅํ ์ ์์ต๋๋ค.
- ๋ณต์ก์ฑ ๊ฐ์: ํด๋ผ์ด์ธํธ๋ ๋จ์ผ API ์๋ํฌ์ธํธ์๋ง ์ํธ ์์ฉํ๋ฉด ๋ฉ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ๋ณต์ก์ฑ: ์คํค๋ง ์คํฐ์นญ์ ์ํคํ ์ฒ์ ๋ณต์ก์ฑ์ ๋ํ ์ ์์ต๋๋ค.
- ์ง์ฐ ์๊ฐ: ๊ฒ์ดํธ์จ์ด ์๋น์ค๋ฅผ ํตํด ์์ฒญ์ ๋ผ์ฐํ ํ๋ฉด ์ง์ฐ ์๊ฐ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์ค๋ฅ ์ฒ๋ฆฌ: ๊ธฐ๋ณธ API์ ์ฅ์ ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๊ฐ๋ ฅํ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํด์ผ ํฉ๋๋ค.
2. ์คํค๋ง ํ๋๋ ์ด์ (Schema Federation)
์คํค๋ง ํ๋๋ ์ด์ ์ ์คํค๋ง ์คํฐ์นญ์ ํ๊ณ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ค๊ณ๋ ์งํ๋ ๋ฐฉ์์ ๋๋ค. ์ด๋ GraphQL ์คํค๋ง๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ๋ ์ ์ธ์ ์ด๊ณ ํ์คํ๋ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
์๋ ๋ฐฉ์:
- ๊ฐ ์๋น์ค๋ GraphQL API๋ฅผ ๋
ธ์ถํ๊ณ ํ๋๋ ์ด์
์ง์๋ฌธ(์:
@key,@extends,@external)์ผ๋ก ์คํค๋ง์ ์ฃผ์์ ๋ต๋๋ค. - ์ค์ ๊ฒ์ดํธ์จ์ด ์๋น์ค(Apollo Federation ์ฌ์ฉ)๋ ์ด๋ฌํ ์ง์๋ฌธ์ ์ฌ์ฉํ์ฌ ์ ์ฒด ํ๋๋ ์ด์ ์คํค๋ง์ ํํ์ธ ์ํผ๊ทธ๋ํ(supergraph)๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
- ๊ฒ์ดํธ์จ์ด ์๋น์ค๋ ์ํผ๊ทธ๋ํ๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ์ ์ ์ ํ ๊ธฐ๋ณธ ์๋น์ค๋ก ๋ผ์ฐํ ํ๊ณ ์ข ์์ฑ์ ํด๊ฒฐํฉ๋๋ค.
์์:
๋์ผํ ์ ์์๊ฑฐ๋ ์์๋ฅผ ์ฌ์ฉํ์ฌ ํ๋๋ ์ด์ ๋ ์คํค๋ง๋ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค.
# Products API
type Product @key(fields: "id") {
id: ID!
name: String!
price: Float!
}
type Query {
product(id: ID!): Product
}
# Users API
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
# Orders API
type Order {
id: ID!
userId: ID!
productId: ID!
quantity: Int!
user: User! @requires(fields: "userId")
product: Product! @requires(fields: "productId")
}
extend type Query {
order(id: ID!): Order
}
ํ๋๋ ์ด์ ์ง์๋ฌธ์ ์ฌ์ฉ์ ์ฃผ๋ชฉํ์ญ์์ค.
@key: ํ์ ์ ๊ธฐ๋ณธ ํค๋ฅผ ์ง์ ํฉ๋๋ค.@requires: ํ๋๊ฐ ๋ค๋ฅธ ์๋น์ค์ ๋ฐ์ดํฐ๋ฅผ ํ์๋ก ํจ์ ๋ํ๋ ๋๋ค.@extends: ์๋น์ค๊ฐ ๋ค๋ฅธ ์๋น์ค์ ์ ์๋ ํ์ ์ ํ์ฅํ ์ ์๋๋ก ํฉ๋๋ค.
์ฅ์ :
- ์ ์ธ์ ๊ตฌ์ฑ: ํ๋๋ ์ด์ ์ง์๋ฌธ์ ์ฌ์ฉํ๋ฉด ์คํค๋ง ์ข ์์ฑ์ ๋ ์ฝ๊ฒ ์ดํดํ๊ณ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ํฅ์: Apollo Federation์ ์ฟผ๋ฆฌ ๊ณํ ๋ฐ ์คํ์ ์ต์ ํํ์ฌ ์ง์ฐ ์๊ฐ์ ์ต์ํํฉ๋๋ค.
- ํฅ์๋ ํ์ ์์ ์ฑ: ์ํผ๊ทธ๋ํ๋ ๋ชจ๋ ํ์ ์ด ์๋น์ค ๊ฐ์ ์ผ๊ด๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ๋๊ตฌ: Apollo Federation ๋๋ ํธํ๋๋ ํ๋๋ ์ด์ ๊ตฌํ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- ๋ณต์ก์ฑ: ์คํค๋ง ์คํฐ์นญ๋ณด๋ค ์ค์ ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- ํ์ต ๊ณก์ : ๊ฐ๋ฐ์๋ ํ๋๋ ์ด์ ์ง์๋ฌธ๊ณผ ๊ฐ๋ ์ ๋ฐฐ์์ผ ํฉ๋๋ค.
3. ๋ชจ๋์ ์คํค๋ง ๋์์ธ
๋ชจ๋์ ์คํค๋ง ๋์์ธ์ ํฌ๊ณ ๋ชจ๋๋ฆฌ์์ธ ์คํค๋ง๋ฅผ ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ๋ชจ๋๋ก ๋๋๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด๋ฅผ ํตํด ํ๋๋ ์ด์ ์คํค๋ง์ ์์กดํ์ง ์๊ณ ๋ API์ ๊ฐ๋ณ ๋ถ๋ถ์ ๋ ์ฝ๊ฒ ์ดํด, ์์ ๋ฐ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ ๋ฐฉ์:
- ์คํค๋ง ๋ด์ ๋ ผ๋ฆฌ์ ๊ฒฝ๊ณ(์: ์ฌ์ฉ์, ์ ํ, ์ฃผ๋ฌธ)๋ฅผ ์๋ณํฉ๋๋ค.
- ๊ฐ ๊ฒฝ๊ณ์ ๋ํด ๋ณ๋์ ๋ชจ๋์ ๋ง๋ค๊ณ ํด๋น ๊ฒฝ๊ณ์ ๊ด๋ จ๋ ํ์ , ์ฟผ๋ฆฌ ๋ฐ ๋ฎคํ ์ด์ ์ ์ ์ํฉ๋๋ค.
- GraphQL ์๋ฒ ๊ตฌํ์ ๋ฐ๋ผ ๊ฐ์ ธ์ค๊ธฐ/๋ด๋ณด๋ด๊ธฐ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ฌ ๋ชจ๋์ ๋จ์ผ ํตํฉ ์คํค๋ง๋ก ๊ฒฐํฉํฉ๋๋ค.
์์ (JavaScript/Node.js ์ฌ์ฉ):
๊ฐ ๋ชจ๋์ ๋ํด ๋ณ๋์ ํ์ผ์ ๋ง๋ญ๋๋ค.
// users.graphql
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
// products.graphql
type Product {
id: ID!
name: String!
price: Float!
}
type Query {
product(id: ID!): Product
}
๊ทธ๋ฐ ๋ค์ ๊ธฐ๋ณธ ์คํค๋ง ํ์ผ์์ ๊ฒฐํฉํฉ๋๋ค.
// schema.js
const { makeExecutableSchema } = require('graphql-tools');
const { typeDefs: userTypeDefs, resolvers: userResolvers } = require('./users');
const { typeDefs: productTypeDefs, resolvers: productResolvers } = require('./products');
const typeDefs = [
userTypeDefs,
productTypeDefs,
""
];
const resolvers = {
Query: {
...userResolvers.Query,
...productResolvers.Query,
}
};
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
module.exports = schema;
์ฅ์ :
- ํฅ์๋ ์ ์ง๋ณด์์ฑ: ์์ ๋ชจ๋์ ์ดํดํ๊ณ ์์ ํ๊ธฐ๊ฐ ๋ ์ฝ์ต๋๋ค.
- ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ: ๋ชจ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ ๋์ ํ์ : ๋ค๋ฅธ ํ์ด ๋ค๋ฅธ ๋ชจ๋์์ ๋ ๋ฆฝ์ ์ผ๋ก ์์ ํ ์ ์์ต๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ์ค๋ฒํค๋: ๋ชจ๋ํ๋ ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ์ฝ๊ฐ์ ์ค๋ฒํค๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ๋ณต์ก์ฑ: ์ํ ์ข ์์ฑ์ ํผํ๊ธฐ ์ํด ๋ชจ๋ ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ์ ์คํ๊ฒ ์ ์ํด์ผ ํฉ๋๋ค.
- ๋๊ตฌ: ๋ชจ๋์ ์คํค๋ง ์ ์๋ฅผ ์ง์ํ๋ GraphQL ์๋ฒ ๊ตฌํ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
4. ์ธํฐํ์ด์ค ๋ฐ ์ ๋์ธ ํ์
์ธํฐํ์ด์ค ๋ฐ ์ ๋์ธ ํ์ ์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ๊ตฌํ๋ ์ ์๋ ์ถ์ ํ์ ์ ์ ์ํ ์ ์์ต๋๋ค. ์ด๋ ๋คํ์ฑ ๋ฐ์ดํฐ, ์ฆ ์ปจํ ์คํธ์ ๋ฐ๋ผ ๋ค๋ฅธ ํํ๋ฅผ ์ทจํ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
์๋ ๋ฐฉ์:
- ๊ณตํต ํ๋ ์งํฉ์ผ๋ก ์ธํฐํ์ด์ค ๋๋ ์ ๋์ธ ํ์ ์ ์ ์ํฉ๋๋ค.
- ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ฑฐ๋ ์ ๋์ธ์ ๋ฉค๋ฒ์ธ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ์ ์ํฉ๋๋ค.
- ๋ฐํ์์ ๊ตฌ์ฒด์ ์ธ ํ์
์ ์๋ณํ๊ธฐ ์ํด
__typenameํ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์์:
interface Node {
id: ID!
}
type User implements Node {
id: ID!
name: String!
email: String!
}
type Product implements Node {
id: ID!
name: String!
price: Float!
}
union SearchResult = User | Product
type Query {
node(id: ID!): Node
search(query: String!): [SearchResult!]!
}
์ด ์์์ User์ Product๋ ๋ชจ๋ ๊ณตํต id ํ๋๋ฅผ ์ ์ํ๋ Node ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํฉ๋๋ค. SearchResult ์ ๋์ธ ํ์
์ User ๋๋ Product์ผ ์ ์๋ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋
๋๋ค. ํด๋ผ์ด์ธํธ๋ `search` ํ๋๋ฅผ ์ฟผ๋ฆฌํ ๋ค์ `__typename` ํ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ค ์ ํ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์ฅ์ :
- ์ ์ฐ์ฑ: ๋คํ์ฑ ๋ฐ์ดํฐ๋ฅผ ํ์ ์์ ๋ฐฉ์์ผ๋ก ํํํ ์ ์์ต๋๋ค.
- ์ฝ๋ ์ฌ์ฌ์ฉ: ์ธํฐํ์ด์ค์ ์ ๋์ธ์์ ๊ณตํต ํ๋๋ฅผ ์ ์ํ์ฌ ์ฝ๋ ์ค๋ณต์ ์ค์ ๋๋ค.
- ํฅ์๋ ์ฟผ๋ฆฌ ๊ฐ๋ฅ์ฑ: ํด๋ผ์ด์ธํธ๊ฐ ๋จ์ผ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ๋ ์ฝ๊ฒ ์ฟผ๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ๋ณต์ก์ฑ: ์คํค๋ง์ ๋ณต์ก์ฑ์ ๋ํ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ: ์ธํฐํ์ด์ค ๋ฐ ์ ๋์ธ ํ์ ์ ํ์ธํ๋ ๊ฒ์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ํ์ธํ๋ ๊ฒ๋ณด๋ค ๋น์ฉ์ด ๋ ๋ง์ด ๋ค ์ ์์ต๋๋ค.
- ๋ด๋ถ ๊ฒ์ฌ(Introspection): ํด๋ผ์ด์ธํธ๊ฐ ๋ฐํ์์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๊ฒฐ์ ํ๊ธฐ ์ํด ๋ด๋ถ ๊ฒ์ฌ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
5. ์ปค๋ฅ์ ํจํด
์ปค๋ฅ์ ํจํด์ GraphQL API์์ ํ์ด์ง๋ค์ด์ ์ ๊ตฌํํ๋ ํ์ค์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค. ๋๊ท๋ชจ ๋ฐ์ดํฐ ๋ชฉ๋ก์ ์ฒญํฌ ๋จ์๋ก ๊ฒ์ํ๋ ์ผ๊ด๋๊ณ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์๋ ๋ฐฉ์:
edges๋ฐpageInfoํ๋๊ฐ ์๋ ์ปค๋ฅ์ ํ์ ์ ์ ์ํฉ๋๋ค.edgesํ๋์๋ ์ฃ์ง ๋ชฉ๋ก์ด ํฌํจ๋๋ฉฐ, ๊ฐ ์ฃ์ง์๋nodeํ๋(์ค์ ๋ฐ์ดํฐ)์cursorํ๋(๋ ธ๋์ ๊ณ ์ ์๋ณ์)๊ฐ ์์ต๋๋ค.pageInfoํ๋์๋ ๋ค์ ํ์ด์ง๊ฐ ์๋์ง ์ฌ๋ถ์ ์ฒซ ๋ฒ์งธ ๋ฐ ๋ง์ง๋ง ๋ ธ๋์ ์ปค์์ ๊ฐ์ ํ์ฌ ํ์ด์ง์ ๋ํ ์ ๋ณด๊ฐ ํฌํจ๋ฉ๋๋ค.- ํ์ด์ง๋ค์ด์
์ ์ ์ดํ๊ธฐ ์ํด
first,after,last,before์ธ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์์:
type User {
id: ID!
name: String!
email: String!
}
type UserEdge {
node: User!
cursor: String!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type Query {
users(first: Int, after: String, last: Int, before: String): UserConnection!
}
์ฅ์ :
- ํ์คํ๋ ํ์ด์ง๋ค์ด์ : API ์ ์ฒด์ ๊ฑธ์ณ ํ์ด์ง๋ค์ด์ ์ ๊ตฌํํ๋ ์ผ๊ด๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
- ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ฒ์: ๋๊ท๋ชจ ๋ฐ์ดํฐ ๋ชฉ๋ก์ ์ฒญํฌ ๋จ์๋ก ๊ฒ์ํ์ฌ ์๋ฒ ๋ถํ๋ฅผ ์ค์ด๊ณ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- ์ปค์ ๊ธฐ๋ฐ ํ์ด์ง๋ค์ด์ : ๊ฐ ๋ ธ๋์ ์์น๋ฅผ ์ถ์ ํ๊ธฐ ์ํด ์ปค์๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ด๋ ์คํ์ ๊ธฐ๋ฐ ํ์ด์ง๋ค์ด์ ๋ณด๋ค ๋ ํจ์จ์ ์ ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ๋ณต์ก์ฑ: ์คํค๋ง์ ๋ณต์ก์ฑ์ ๋ํ ์ ์์ต๋๋ค.
- ์ค๋ฒํค๋: ์ปค๋ฅ์ ํจํด์ ๊ตฌํํ๊ธฐ ์ํด ์ถ๊ฐ ํ๋์ ํ์ ์ด ํ์ํฉ๋๋ค.
- ๊ตฌํ: ์ปค์๊ฐ ๊ณ ์ ํ๊ณ ์ผ๊ด๋๋๋ก ์ ์คํ ๊ตฌํ์ด ํ์ํฉ๋๋ค.
๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ GraphQL ์คํค๋ง๋ฅผ ๋์์ธํ ๋ ๋ค์ ์ถ๊ฐ ์์๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
- ํ์งํ(Localization): ๋ค๋ฅธ ์ธ์ด์ ์ง์ญ์ ์ง์ํ๊ธฐ ์ํด ์ง์๋ฌธ์ด๋ ์ฌ์ฉ์ ์ ์ ์ค์นผ๋ผ ํ์ ์ ์ฌ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ค๋ฅธ ์ธ์ด์ ๋ํ ๋ฒ์ญ์ ์ ์ฅํ๋ ์ฌ์ฉ์ ์ ์ `LocalizedText` ์ค์นผ๋ผ๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
- ์๊ฐ๋: ํ์์คํฌํ๋ฅผ UTC๋ก ์ ์ฅํ๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํ์ ๋ชฉ์ ์ผ๋ก ์์ ์ ์๊ฐ๋๋ฅผ ์ง์ ํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค.
- ํตํ: ์ผ๊ด๋ ํตํ ํ์์ ์ฌ์ฉํ๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํ์ ๋ชฉ์ ์ผ๋ก ์ ํธํ๋ ํตํ๋ฅผ ์ง์ ํ ์ ์๋๋ก ํฉ๋๋ค. ์ด๋ฅผ ๋ํ๋ด๊ธฐ ์ํด ์ฌ์ฉ์ ์ ์ `Currency` ์ค์นผ๋ผ๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
- ๋ฐ์ดํฐ ์์ฃผ(Data residency): ๋ฐ์ดํฐ๊ฐ ํ์ง ๊ท์ ์ ์ค์ํ์ฌ ์ ์ฅ๋๋๋ก ํฉ๋๋ค. ์ด๋ฅผ ์ํด API๋ฅผ ์ฌ๋ฌ ์ง์ญ์ ๋ฐฐํฌํ๊ฑฐ๋ ๋ฐ์ดํฐ ๋ง์คํน ๊ธฐ์ ์ ์ฌ์ฉํด์ผ ํ ์ ์์ต๋๋ค.
- ์ ๊ทผ์ฑ: ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๊ฐ ์ ๊ทผํ ์ ์๋๋ก ์คํค๋ง๋ฅผ ๋์์ธํฉ๋๋ค. ๋ช ํํ๊ณ ์ค๋ช ์ ์ธ ํ๋ ์ด๋ฆ์ ์ฌ์ฉํ๊ณ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๋ ๋์ฒด ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์ ํ ์ค๋ช ํ๋๋ฅผ ๊ณ ๋ คํด ๋ณด๊ฒ ์ต๋๋ค.
type Product {
id: ID!
name: String!
description(language: String = "en"): String!
}
์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ๋ ํน์ ์ธ์ด๋ก ์ค๋ช ์ ์์ฒญํ ์ ์์ต๋๋ค. ์ธ์ด๊ฐ ์ง์ ๋์ง ์์ ๊ฒฝ์ฐ ์์ด(`en`)๊ฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
๊ฒฐ๋ก
ํ์ฅ ๊ฐ๋ฅํ ์คํค๋ง ๋์์ธ์ ๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๊ตฌ ์ฌํญ์ ์ฒ๋ฆฌํ ์ ์๋ ๊ฐ๋ ฅํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ GraphQL API๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์ด ๊ธ์์ ์ค๋ช ํ ์์น์ ๋ฐ๋ฅด๊ณ ์ ์ ํ ๋์์ธ ํจํด์ ์ฌ์ฉํจ์ผ๋ก์จ, ์ดํดํ๊ณ , ์์ ํ๊ณ , ํ์ฅํ๊ธฐ ์ฌ์ฐ๋ฉด์๋ ๋ฐ์ด๋ ์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์ ์ ๊ณตํ๋ API๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์คํค๋ง๋ฅผ ๋ชจ๋ํํ๊ณ , ๊ตฌ์ฑํ๊ณ , ์ถ์ํํ๋ฉฐ, ๊ธ๋ก๋ฒ ์ฌ์ฉ์์ ํน์ ์๊ตฌ๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ ๊ธฐ์ตํ์ญ์์ค.
์ด๋ฌํ ํจํด์ ์ฑํํจ์ผ๋ก์จ GraphQL์ ์ ์ฌ๋ ฅ์ ์ต๋ํ ๋ฐํํ๊ณ ์์ผ๋ก ์๋ ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ๋ํ ์ ์๋ API๋ฅผ ๊ตฌ์ถํ ์ ์์ต๋๋ค.